#ifndef _PGACCESS_H_
#define _PGACCESS_H_

#include <buildspec.h>
#include <Client/ClientUtils/Network/AbstractRDBAccess.h>

namespace GST {

	//prototypes:
	namespace ClientGUI	{
		class ProgressControl;
	}

namespace ClientUtils {

	class PostgresDriver;

	/**
	  * Used to pass SSL settings to the libpq driver for PostgreSQL connections (using PGAccess).
	  *
	  * For detailed information about SSL on postgres please consult the postgres man pages:
	  *    http://www.postgresql.org/docs/9.1/static/libpq-ssl.html
	  */
    struct GST_API_EXPORT PGSSLConfig
	{
		enum Mode{
			SSLDISABLED   /// <b>Eavesdropping protection</b>=NO, <b>MITM protection</b>=NO, <b>I don't care about security, and I don't want to pay the overhead of encryption.</b>
			, SSLREQUIERED  /// <b>Eavesdropping protection</b>=Yes, <b>MITM protection</b>=No, <b>I want my data to be encrypted, and I accept the overhead. I trust that the network will make sure I always connect to the server I want.</b>
			, SSLVERIFYCA   /// <b>Eavesdropping protection</b>=Yes, <b>MITM protection</b>=Depends on CA-policy, <b> 	I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server that I trust.</b>
			, SSLVERIFYALL  /// <b>Eavesdropping protection</b>=Yes, <b>MITM protection</b>=Yes, <b>I want my data encrypted, and I accept the overhead. I want to be sure that I connect to a server I trust, and that it's the one I specify.</b>
		};

		///SSL Modes supported by libpq
		Mode mode;
		///Set to true or false weither to set compression on (slower) or off (faster)
		bool compression;
		///local path to: client certificate (sample: ~/.postgresql/postgresql.crt); \n requested by server
		std::string crtfile;
		///local path to: client private key (sample: ~/.postgresql/postgresql.key); \n proves client certificate sent by owner; does not indicate certificate owner is trustworthy
		std::string keyfile;
		///local path to: trusted certificate authorities (sample: ~/.postgresql/root.crt); \n checks that server certificate is signed by a trusted certificate authority
		std::string rootcertfile;
		///local path to: certificates revoked by certificate authorities (sample: ~/.postgresql/root.crl); \n server certificate must not be on this list
		std::string crlfile;

        ///returns the libpq version used by GST API
		static float libpqVersion;
        std::string ToConnectionString();

	};
	typedef boost::shared_ptr<PGSSLConfig> PGSSLConfigPtr;

	struct GST_API_EXPORT PGRecordFeature
		: public CrudeFeature
	{
		AbstractDataTablePtr data;
		TableAttributeValListPtr objProperties;

		virtual std::string GetGeometry();
		virtual std::string GetPropertyVals();
		virtual std::string GetLockId();
		virtual TableAttributeValListPtr GetObjProperties() { return objProperties; }
	};


	/**
	 * Base class handle NetworkInterface functions and implement those to direct connected
	 * Relational Database backend. Its derived classes need overload functions which
	 * using SQL slang or DB specific behavior like getCurrentUser().
	 */
	class GST_API_EXPORT PGAccess
		: public AbstractRDBAccess
	{
	public:
		PGAccess( HostPtr host, const std::string& DB, RDBConfigPtr dbconfig );
		PGAccess( const PostgresDriver& driver, RDBConfigPtr dbconfig );
		
		///@name DB specific NetworkInterface implementations
		//@{
		virtual NetworkPtr fork() const;
		virtual NetworkPtr reconnect(const std::string & user, const std::string & pwd, const std::string & db="") const;
		virtual bool isSSLUsed() const;
		virtual bool isSuperUserConnection() const;
		virtual UserPtr getCurrentGSTUser() const;
		virtual BackendType GetBackendType() const
		{
			return NetworkInterface::BackendTypePG;
		}

		///@name DB specific NetworkInterface implementations
		//@{
		virtual void CreateFeatureClass_Impl( const FeatureClassDetailedDesc& featureClassDesc );
		virtual void CreatePropertyTable( const FeatureClassDesc& featureClass, const GeoColumnDesc & geocolumn );
		virtual CrudeFeaturePtr GetFeature( const FeatureDesc & feature , const IGeometry::RequestFormat & geometryformat, Geometry::SRSPtr srs, bool lock = false, QueryBoxPtr queryBox = QueryBoxPtr(), long commitKey = -1 );
		virtual void SimplifyFeature( const FeatureDesc & feature );
		virtual FeatureDescPtr UploadNewFeature( const Geometry::StreamableGeometry & feature, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
		virtual void UpdateFeature( const Geometry::StreamableGeometry & feature, const std::string & lockid, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );

		virtual void UpdateFeatureKeepLock( const Geometry::StreamableGeometry & feature, const std::string & lockid, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
		virtual void UnlockByKey( const std::string & key );
		virtual void ExecuteScript( const std::string & script );
		virtual CrudeFeaturePtr GetFeatureBinary( const FeatureDesc & feature, Geometry::SRSPtr srs, QueryBoxPtr queryBox = QueryBoxPtr(), long commitKey = -1);
		virtual NamesListPtr ListAllTables() const ;
		virtual bool ViewRefersTable(const std::string& tablename, const std::string& viewname) const;
		virtual NamesListPtr ListAllViewsRefersTable(const std::string& tablename) const;

		virtual NamesListPtr ListAllColumns(const std::string& tablename) const;
		virtual NamesListPtr ListPrimaryKeyColumns(const std::string& tablename) const;
		virtual std::string GetExactColumnDataType(const std::string& columnname) const;
		virtual ClientUtils::TableAttributeDesc::DType GetColumnDType(const std::string& columnname) const ;
		virtual void RenameProperty_Impl( const FeatureClassDesc& featureClass, TableAttributeDescPtr attribute, const std::string& newName ) const;

		virtual ServiceDescriptionPtr CreateService(const std::string &name, const std::string &url, long accessLevelId, const std::string &user, const std::string &secret) const;
		virtual ServiceDescriptionPtr UpdateService(long serviceId, const std::string &name, const std::string &url, long accessLevelId, const std::string &user, const std::string &secret) const;


			///@name user handling
			//@{
				virtual UserListPtr GetUsersByGroup( const std::string& groupName ) const;
				virtual GroupListPtr GetGroupsByUser( const std::string& userName) const;
				virtual GroupListPtr GetGroupsByCurrentUser() const;

				virtual void ChangeUserPassword(const std::string& userName, const std::string &newPassword, const std::string &oldPassword) const;
			//@}

			///@name Version handling
			//@{
			virtual Utils::GSTVersionPtr GetStorageVersion() const;
			virtual int CheckCompatibility(const std::string &client_version) const;
			//@}
		//@}

		///@name Version MoMa
		//@{
		virtual LinkAdjacencyPtr CreateLinkAdjacency(LinkAdjacency::LinkId parent, LinkAdjacency::ReferId refId, LinkAdjacency::TargetType refTarget, Owner::OwnerId owner) const;
		virtual ColorScale::ColorScaleId AddColorScale(ColorScalePtr cs) const;
		virtual ColorValue::ColorValueId AddColorValue(ColorValuePtr cv) const;
		virtual FeatureLinkIdGeometryIdPairListPtr ResolveGeometries( LinkAdjacency::LinkId rootElement, LinkAdjacency::LinkId csRootElement = ROOT_NODE_LINKID, ColorScale::ColorScaleId csRootScale = -1 ) const;
		virtual CrudeFeaturePtr GetFeatureFromMoMa(	LinkAdjacency::LinkId flid
													, const IGeometry::RequestFormat & geometryformat
													, Geometry::SRSPtr srs
													, LinkAdjacency::LinkId csRootElement = ROOT_NODE_LINKID
													, ColorScale::ColorScaleId csRootScale = -1
													, bool lock = false
													, QueryBoxPtr queryBox = QueryBoxPtr() 
													, long commitKey = -1) const;
		virtual QueryBoxPtr GetBboxFromMoma(const MoMaKey &momakey,
											Geometry::SRSPtr targetSrs) const;
		virtual void CreateElement(ElementPtr elment, bool uniqueName = false) const;
		virtual MoMaPropertyDescPtr CreateMoMaPropertyDesc(const std::string& name, TableAttributeDesc::DType dtype, Owner::OwnerId owner) const;
		virtual MoMaPropertyValueListPtr GetMoMaPropertyValuesForNode(const LinkedElement& element) const;

		//@}

		///@name Versioning
		//@{
		virtual long BeginCommit(const std::string &message) const;
		virtual int EndCommit(long commitKey) const;
		//@}

		///@name AbstractRDBAccess interface
		//@{
		virtual RDBDriverInterface * getRDBDriver() const;
		virtual void RunPreparedInsertStatement(const InsertStatementDesc & preparedStatement);
		virtual void RunPreparedUpdateStatement(const UpdateStatementDesc & preparedStatement);
		//@}

		void SetSSLConfig( PGSSLConfigPtr config );
		bool isSSLConfig() const;

		virtual void updateSchemaStats() const;

		/**
		  * creates a database testDB as template from templateDB.
		  */
		void CreateTestDatabase( const std::string & templateDB, const std::string & testDB );

		/**
		  * drop the database testDB.
		  * @note use the method careful!
		  */
		void DropTestDatabase( const std::string & testDB );
	protected:

		///@name virtual helpers
		//@{
		virtual AbstractRDBAttributeVal * newAttributeVal(const TableAttributeVal & val) const;
		virtual AbstractRDBAttributeDesc * newAttributeDesc(const TableAttributeDesc & desc, bool is_primaryKey=false) const;
		virtual void RunSP(SPDescPtr storedProcedure) const;
		virtual void RenameFeatureClass_Impl( const FeatureClassDesc& featureClassDesc, const std::string& newName );
		virtual TableAttributeDescListPtr GetPrimaryKey(const std::string & tablename) const;
		//@}

		///@name Slices/Sections helper
		//@{
		virtual ColorMap::Id InsertColorMap(  const std::string & name, const Geometry::IGeometry::Color & nodataColor, const std::string &regex, long accessLevelId );
		void UpdateFeature_impl( const Geometry::StreamableGeometry & feature, const std::string & lockid, bool keepLock, const FeatureClassDesc & target, long commitKey = -1, bool updateStats = true );
		//@}

	private:

		RDBConfigPtr getConfig() const;
		PostgresDriver * getDriver() const;
		///@name SQL generation helper
		//@{
		virtual std::string GenSQLAddColumn( const std::string & table, const TableAttributeDesc& attribute );
		virtual void GenSQLForeignKeyConstraint(ForeignKeyPtr kc, const std::string& cpname, std::string& sql_OUT);
		virtual std::string GenSQLDeleteColumn(ForeignKeyPtr fk);
		virtual std::string GenSQLEndTransaction(const std::string& errormessage="");
		virtual std::string GenSQLBeginTransaction();
		//@}

		///@name local helpers
		//@{
		virtual void constructVariousPropertyNameAndValueList( bool updateSyntax, Geometry::StreamableGeometry::KeyValueListPtr variousProperties, TableAttributeDescListPtr attributes, std::string &variousPropertiesNames, std::string &variousPropertiesValues, const std::string & ignore, const std::string & warn_methodname, const bool executeimmediatesyntax = false ) const;
		virtual GST::Protocol GetProtocol() const;
		void handleExceptions(const std::string &functionName, const std::string &sprocName = std::string()) const;
		//@}
	};

} //of ns ClientUtils
} //of ns GST

#endif //_DIRECT_RDB_ACCESS_H_
